/*
 *  modifier: Honrun
 *  date:     2021/12/21 20:42
 */
#include "stdio.h"
#include "stdint.h"
#include "DevicesMemHeap.h"


MemHeapType g_typeMemHeapHead = {0};
/* 需要增加 sizeof(MemHeapType) * 2 个长度，以使字节对齐，以及存储管理信息 */
static uint8_t st_MemHeap[DEVICES_MEM_LENGTH + sizeof(MemHeapType) * 2] = {0};


void vMemHeapInit(void)
{
    vMemHeapCreate(&g_typeMemHeapHead, st_MemHeap, DEVICES_MEM_LENGTH);
}

static int8_t cMemSet(void *pvMemAddr, int32_t iValue, int32_t iSize)
{
    uint32_t *puiData = pvMemAddr;

    if((pvMemAddr == NULL) || (iSize < 0))
        return -1;

    iSize /= 4;
    while((iSize--) > 0)
    {
        *puiData++ = iValue;
    }

    return 0;
}

static void *pvMemCpy(void *pvMemTargetAddr, void *pvMemSourceAddr, int32_t iSize)
{
    uint32_t *puiTargetData = pvMemTargetAddr, *puiSourceData = pvMemSourceAddr;

    if((pvMemTargetAddr == NULL) || (pvMemSourceAddr == NULL) || (iSize < 0))
        return NULL;

    iSize /= 4;
    while((iSize--) > 0)
    {
        *puiTargetData++ = *puiSourceData++;
    }

    return pvMemTargetAddr;
}

void vMemHeapCreate(MemHeapType *ptypeMemHanle, uint8_t *pucMemHeap, int32_t iLength)
{
    MemHeapType *ptypeMemNow = NULL;

    if((ptypeMemHanle == NULL) || (pucMemHeap == NULL) || (iLength <= 0))
        return;

    /* 地址 N 字节对齐 */
    ptypeMemHanle->startAddr = memHeapRoundUp((uint32_t)pucMemHeap, MEM_HEAP_ROUNDUP_VALUE);
    ptypeMemHanle->stopAddr  = ptypeMemHanle->startAddr + iLength;

    /* 初始化第一个空闲空间 */
    ptypeMemNow  = (MemHeapType *)ptypeMemHanle->startAddr;
    *ptypeMemNow = *ptypeMemHanle;

    /* 初始化内存空间末尾的管理信息，标志为已使用是为了在遍历时方便判断退出，以及方便free函数判断 */
    ptypeMemNow  = (MemHeapType *)ptypeMemHanle->stopAddr;
    *ptypeMemNow = *ptypeMemHanle;
    /* 起始地址最低置1，表示已使用 */
    ptypeMemNow->startAddr |= 1;
}

void *pvMemHeapMalloc(MemHeapType *ptypeMemHanle, int32_t iSize)
{
    void *pvHandle = NULL;
    MemHeapType *ptypeMemNow = NULL, *ptypeMemNext = NULL, *ptypeMemMin = NULL;
    uint32_t uiAddrStop = 0;
    int32_t iSizeNow = 0, iSizeMin = 0x7FFFFFFF;

    if((ptypeMemHanle == NULL) || (iSize <= 0))
        return NULL;

    /* 长度 N 字节对齐 */
    iSize = memHeapRoundUp(iSize, MEM_HEAP_ROUNDUP_VALUE);

    /* 遍历mem空间 */
    for(ptypeMemNow = (MemHeapType *)ptypeMemHanle->startAddr; (uint32_t)ptypeMemNow < ptypeMemHanle->stopAddr; ptypeMemNow = (MemHeapType *)ptypeMemNow->stopAddr)
    {
        if((ptypeMemNow->startAddr & 1) == 0)
        {
            iSizeNow = ptypeMemNow->stopAddr - ptypeMemNow->startAddr - sizeof(MemHeapType);

            /* 最小空闲匹配 */
            if((iSizeNow >= iSize) && (iSizeMin > iSizeNow))
            {
                iSizeMin = iSizeNow;
                ptypeMemMin = ptypeMemNow;

                /* 找到刚好相同大小的空闲空间就直接退出遍历 */
                if(iSizeMin == iSize)
                    break;
            }
        }
    }

    /* 没匹配到合适的最小空间，表示当前分配不了 */
    if(ptypeMemMin == NULL)
        return NULL;

    /* 最小匹配空间被划分后还有剩余空间，并能够存储下一个头部信息 */
    if((iSizeMin - iSize) >= sizeof(MemHeapType))
    {
        uiAddrStop = ptypeMemMin->stopAddr;
        ptypeMemMin->stopAddr = ptypeMemMin->startAddr + sizeof(MemHeapType) + iSize;

        ptypeMemNext = (MemHeapType *)ptypeMemMin->stopAddr;
        ptypeMemNext->startAddr = ptypeMemMin->stopAddr;
        ptypeMemNext->stopAddr  = uiAddrStop;
    }
    /* 扩容，不遗留用不上的小空闲空间 */
    else
    {
        ptypeMemMin->stopAddr = ptypeMemMin->startAddr + sizeof(MemHeapType) + iSizeMin;
    }

    /* 返回空间管理信息之后的空间地址 */
    pvHandle = (void *)(ptypeMemMin->startAddr + sizeof(MemHeapType));

    /* 起始地址最低置1，表示已使用 */
    ptypeMemMin->startAddr |= 1;

    return pvHandle;
}

void *pvMemHeapCalloc(MemHeapType *ptypeMemHanle, int32_t iNumber, int32_t iSize)
{
    void *pvHandle = NULL;
    int32_t iLength = iNumber * iSize;

    /* 长度 N 字节对齐 */
    iLength = memHeapRoundUp(iLength, MEM_HEAP_ROUNDUP_VALUE);

    pvHandle = pvMemHeapMalloc(ptypeMemHanle, iLength);

    if(pvHandle != NULL)
    {
        cMemSet(pvHandle, 0, iLength);
    }

    return pvHandle;
}

void *pvMemHeapRealloc(MemHeapType *ptypeMemHanle, void *pvMemAddr, int32_t iSize)
{
    void *pvHandle = NULL;
    MemHeapType *ptypeMemOld = NULL, *ptypeMemNow = NULL, *ptypeMemNext = NULL;
    uint32_t uiAddrStart = 0;
    int32_t iNewSize = 0;

    if((ptypeMemHanle == NULL) || (pvMemAddr == NULL) || (iSize <= 0))
        return NULL;

    /* 位移到头部管理信息位置 */
    uiAddrStart = (uint32_t)(pvMemAddr - sizeof(MemHeapType));
    if((uiAddrStart < ptypeMemHanle->startAddr) || (uiAddrStart > ptypeMemHanle->stopAddr))
        return NULL;

    ptypeMemOld = (MemHeapType *)(uiAddrStart);

    /* 长度 N 字节对齐 */
    iSize = memHeapRoundUp(iSize, MEM_HEAP_ROUNDUP_VALUE);

    /* 计算后续衔接空闲空间的大小 */
    for(ptypeMemNow = (MemHeapType *)ptypeMemOld->stopAddr; (ptypeMemNow->startAddr & 1) == 0; ptypeMemNow = (MemHeapType *)(ptypeMemNow->stopAddr));

    uiAddrStart = ptypeMemOld->startAddr & 0xFFFFFFFE;
    iNewSize = (uint32_t)ptypeMemNow - uiAddrStart - sizeof(MemHeapType);

    /* 直接拓展衔接的空闲空间 */
    if(iNewSize >= iSize)
    {
        /* 最小匹配空间被划分后还有剩余空间，并能够存储下一个头部信息 */
        if((iNewSize - iSize) >= sizeof(MemHeapType))
        {
            ptypeMemOld->stopAddr = uiAddrStart + sizeof(MemHeapType) + iSize;

            ptypeMemNext = (MemHeapType *)ptypeMemOld->stopAddr;
            ptypeMemNext->startAddr = ptypeMemOld->stopAddr;
            ptypeMemNext->stopAddr  = (uint32_t)ptypeMemNow;
        }
        /* 扩容，不遗留用不上的小空闲空间 */
        else
        {
            ptypeMemOld->stopAddr = uiAddrStart + sizeof(MemHeapType) + iNewSize;
        }

        return pvMemAddr;
    }
    /* 重新分配空间 */
    else
    {
        /* 分配不到满足所需大小的空间 */
        if((pvHandle = pvMemHeapMalloc(ptypeMemHanle, iSize)) == NULL)
            return NULL;

        /* 转移拷贝数据 */
        iSize = ptypeMemOld->stopAddr - uiAddrStart - sizeof(MemHeapType);
        pvMemCpy(pvHandle, pvMemAddr, iSize);

        /* 释放旧空间 */
        vMemHeapFree(ptypeMemHanle, pvMemAddr);

        return pvHandle;
    }
}

void vMemHeapFree(MemHeapType *ptypeMemHanle, void *pvMemAddr)
{
    MemHeapType *ptypeMemNow = NULL, *ptypeMemPrev = NULL, *ptypeMemNext = NULL;
    uint32_t uiAddrStart = 0;

    if((ptypeMemHanle == NULL) || (pvMemAddr == NULL))
        return;

    /* 位移到头部管理信息位置 */
    uiAddrStart = (uint32_t)(pvMemAddr - sizeof(MemHeapType));
    if((uiAddrStart < ptypeMemHanle->startAddr) || (uiAddrStart > ptypeMemHanle->stopAddr))
        return;

    ptypeMemNow = (MemHeapType *)(uiAddrStart);

    /* 最低位清零，表示释放此片内存 */
    ptypeMemNow->startAddr &= 0xFFFFFFFE;

    /* 遍历，找到当前待删除空间的前面一个空间 */
    for(ptypeMemPrev = (MemHeapType *)ptypeMemHanle->startAddr; ptypeMemPrev->stopAddr < ptypeMemNow->startAddr; ptypeMemPrev = (MemHeapType *)ptypeMemPrev->stopAddr);

    /* 合并前面一个相连的空闲空间 */
    if((ptypeMemPrev->startAddr & 1) == 0)
    {
        ptypeMemPrev->stopAddr = ptypeMemNow->stopAddr;
        ptypeMemNow = ptypeMemPrev;
    }

    /* 合并后面一个相连的空闲空间 */
    ptypeMemNext = (MemHeapType *)ptypeMemNow->stopAddr;
    if((ptypeMemNext->startAddr & 1) == 0)
    {
        ptypeMemNow->stopAddr = ptypeMemNext->stopAddr;
    }
}
